package xin.nick.system.filter;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import xin.nick.common.core.constant.SystemConstants;
import xin.nick.common.core.entity.HttpServletRequestParamWrapper;
import xin.nick.common.core.util.IpUtil;
import xin.nick.system.domain.dto.LoginDTO;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Enumeration;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 2024年2月26日,弃用
 * 使用 JsonLoginFilter ,通过 继承 UsernamePasswordAuthenticationFilter 实现登录
 * @author Nick
 * @since 2023/11/14
 */
@Slf4j
//@Component
@RequiredArgsConstructor
public class LoginFilter extends OncePerRequestFilter {

    private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login",
            "POST");

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        // 这里主要是从请求的BODY中获取登录信息,默认Security是从 Param 中获取用户密码信息的
        // 其实也没必要这么做,可以自己去实现登录流程

        log.debug("请求头: {}", JSON.toJSONString(request.getHeaderNames()));
        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String headName = headerNames.nextElement();
            Enumeration<String> headerValueList = request.getHeaders(headName);
            while (headerValueList.hasMoreElements()) {
                String headerValue = headerValueList.nextElement();
                log.debug("{}: {}", headName, headerValue);
            }
        }

        // 1.非 /login 直接跳过
        // 2.只允许POST方法调用 /login

        // 只处理 login 请求
        if (DEFAULT_ANT_PATH_REQUEST_MATCHER.matches(request)) {

            String requestUri = request.getRequestURI();
            log.info("loginFilter: 处理用户登录 ip: {}, uri: {},",
                    IpUtil.getIpAddress(request),
                    requestUri
            );

            // tips 这里可以补充验证码处理逻辑

            // 获取body 数据 转换为 dto
//            request.getInputStream().
            String bodyString = new BufferedReader(new InputStreamReader(request.getInputStream())).lines().collect(Collectors.joining());
            if (StrUtil.isBlank(bodyString)) {
                filterChain.doFilter(request, response);
                return;
            }

            LoginDTO dto = JSON.parseObject(bodyString, LoginDTO.class);
            if (Objects.isNull(dto)) {
                filterChain.doFilter(request, response);
                return;
            }

            // 包装了 param 的 request
            HttpServletRequestParamWrapper httpServletRequestWrapper = new HttpServletRequestParamWrapper(request);
            Map<String, String[]> parameterMap = httpServletRequestWrapper.getParameterMap();


            // 将 body 获取到的 登录信息放入 param
            String username = dto.getUsername();
            String password = dto.getPassword();
            parameterMap.put(SystemConstants.SPRING_SECURITY_FORM_USERNAME_KEY, new String[]{username});
            parameterMap.put(SystemConstants.SPRING_SECURITY_FORM_PASSWORD_KEY, new String[]{password});
            httpServletRequestWrapper.setParameterMap(parameterMap);

            filterChain.doFilter(httpServletRequestWrapper, response);
        } else {
            filterChain.doFilter(request, response);
        }

    }
}
